/**
 * Model Handles db model
 * @author: nicos.giuliani@logn.ch
 * @version: 1.0
 */
var Model = function(model) {
	
	this.data = model;
	this.running = undefined,
	this.maxSize = 5 * 1024 * 1024, // 5 Mbytes
	this.db = null;
	this.hasChanged = true;
	
	eval('var settings = ' + load('protected/config/main.js').response.removeComments().removeTabs());
	
	if(!this.data.name)return;
	
	if(model.methods) {
		this.methods = model.methods;
	}
	
	this.open = function() {
		this.db = openDatabase(settings.name, settings.version, settings.description, this.maxSize);		
	};

	this.create = function() {
		
		var field, sql = "CREATE TABLE IF NOT EXISTS " + this.data.name + '(';
		
		this.data.fields.push({id:'INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT'}); // Always add a primary key	

		for(var i in this.data.fields) {
			
			field = this.data.fields[i];
			
			for(var k in field) {
				
				sql += k + ' ' + field[k]+',';	
			}
		}	
		sql = sql.substr(0,sql.length-1)+')';
		
		this.db.transaction(function(tx) {
			
			tx.executeSql(sql, [], null, function(e) {
				console.log('Error creating table. sql: '+sql);
			});
		});
		this.hasChanged = true;		
	};
	
	this.execute = function(sql, params, callback, fail) {
		
		var self = this, args = arguments;
		
		try {
			this.db.transaction(function(tx) {
				tx.executeSql(sql, params, callback?callback:function(){}, fail ? fail : function(tx, e) { console.log('Error while executing sql. Error '+e.message) });
			});
			return true;
		} catch(e) {
			return false;
		}		
	};
	
	this._getFieldNames = function() {
		
		var fields = this.data.fields, res = [];
		
		for(var i = 0; i < fields.length; i++) {
			
			for(var j in fields[i]) {
				
				res.push(j);
			}
		}		
		return res;
	};
	
	/** 
	 * Get all db occurrences and transforms them to an array of object model.
	 * @param: Function {callback}
	 * @return: void()
	 */
	this.getAll = function(callback, fields, sql) {
		
		var self = this, 
			_sql = 'SELECT '  + (!fields ? "*" : fields) + ' FROM '+ 
				  this.data.name + ' ' + (sql ? sql : '');

		// Execute query internally
		this.execute(_sql, [], function(tx, res) {
				
				var row, object, results = [];
				
				// Goes through all db rows
				for(var i = 0; i < res.rows.length; i++) {
					
					row = res.rows.item(i);
					object = {};
					
					// Goes through field's name & build the object
					for(var j in row) {
						
						object[j] = row[j];	
					}
					results.push(object);
				}
				callback(results);
			}
		);
	};
	
	this.add = function(o, callback) {
		
		var sql = '', values = [];
		
		for(var i in o) {
			sql += i+',';
			values.push(o[i]);
		}

		sql = sql.substr(0,sql.length-1);
		this.addBySQL(values, sql, callback);
	};
	
	this.addBySQL = function(values, fields, callback) {
		
		var field, self = this, sql = "INSERT INTO " + this.data.name + ' (' + (fields ? ' '+fields+' ' : '') , val = 'VALUES (';
		if(!fields) {
			
			for(var i in this.data.fields) {
				
				field = this.data.fields[i];
				if(field.id) continue;
				
				for(var k in field) {
	
					sql += k + ',';	
				}
				val += '?,';
			}	
		} else {
			var tmp = fields.split(',');
			for(var i=0;i< tmp.length;i++) {
				val += '?,';
			}
		}
		sql = sql.substr(0,sql.length-1)+') '+ val.substr(0, val.length -1)+')';
		this.execute(sql, values, callback ? callback : null,
			
			function(tx, err) {
				throw 'Error while adding a ' + self.data.name +'. Error: '+err.message +'; SQL: '+sql;
			}
		);
		this.hasChanged = true;
	};

	this.delete = function(id) {
		this.execute('DELETE FROM '+this.data.name+' WHERE id = '+id, []);
		this.hasChanged = true;
	};
		
	this.update = function(id, values, callback) {
		
		var field, sql = 'UPDATE '+this.data.name+' SET ', vals = [];
		
		for(var i in values) {
			sql += i + '=?,';
			vals.push(values[i]);
		}		
		sql = sql.substr(0,sql.length-1)+(id ? ' WHERE id='+id: '');
		this.execute(sql, vals, callback ? callback : null, function(tx,e) { console.log('Error while updating '+e.message)});
		this.hasChanged = true;
	};
	
	try {
		
		if (!window.openDatabase) {
			console.log('Databases are not supported in this browser.');
			return;
		}
		this.open();
		
		if(!this.running) {
			
			this.create();
			this.running = true;
		}
		
	} catch(e) {

		if (e == 2) {
			// Version number mismatch.
			console.log("Invalid database version.");
			return;
		} 
		console.log("Unknown error " + e + ".");
		return;
	}	
};
